package es.unileon.rnag.jgen.operadores;

import java.util.ArrayList;
import java.util.List;

import es.unileon.rnag.jgen.Cromosoma;
import es.unileon.rnag.jgen.genes.Gen;

/**
 * Clase que implementa el Crossover con dos puntos de corte
 * @author Abel Mayorga Gonz&aacute;lez
 * @author Sergio Fern&aacute;ndez Mart&iacute;nez
 * @version 1.0
 */
public class CrossoverDosPuntos extends Crossover {

	/**
	 * Constructor
	 * @param p: Probabilidad de crossover en tanto por 1
	 */
	public CrossoverDosPuntos(float p) {
		super(p);
	}

	@Override
	public List<Cromosoma> operar(int generacion, List<Cromosoma> poblacion) {
		List<Cromosoma> hijos = new ArrayList<Cromosoma>();
		List<Cromosoma> listaCross = new ArrayList<Cromosoma>();
		List<Cromosoma> listaNoCross = new ArrayList<Cromosoma>();
		//Se escinde la poblacion en dos listas
		for(Cromosoma c: poblacion){
			if(Math.random()<_prob){
				listaCross.add(c);
			} else {
				listaNoCross.add(c);
			}
		}
		//Si el numero de individuos en la lista de crossover no es par
		//Se añade uno aleatoriamente de la otra lista
		if(listaCross.size()%2!=0){
			listaCross.add(listaNoCross.remove((int)Math.random()*listaNoCross.size()));
		}
		while(listaCross.size()>0){
			//Se cogen dos cromosomas aleatoriamente
			Cromosoma c1 = listaCross.remove((int)(Math.random()*listaCross.size()));
			Cromosoma c2 = listaCross.remove((int)(Math.random()*listaCross.size()));
			//Se obtienen sus genes
			Gen[] g1 = c1.getGenes();
			Gen[] g2 = c2.getGenes();
			//Se obtienen dos puntos de corte
			int corte1 = (int)(Math.random()*(g1.length-1));
			int corte2 = (int)(Math.random()*(g1.length-1));
			//El punto de corte 2 tiene que ser mayor que el punto de corte 1
			while(corte1 == corte2){
				corte2 = (int)(Math.random()*(g1.length-1));
			}
			if(corte2 < corte1){
				int temp = corte1;
				corte1 = corte2;
				corte2 = temp;
			}
			//Se intercambian los genes entre los puntos de corte
			for(int i = corte1+1; i <= corte2; i++){
				Gen temp = g2[i];
				g2[i] = g1[i];
				g1[i] = temp;
			}
			//Se añaden a la lista de hijos
			hijos.add(c1);
			hijos.add(c2);
		}
		//Se completa la lista con los que no se han cruzado
		hijos.addAll(listaNoCross);
		return hijos;
		
	}

}
